package zmee.pmct.opplugin;

import cn.hutool.http.HttpRequest;
import com.alibaba.druid.support.logging.Log;
import com.alibaba.druid.support.logging.LogFactory;
import kd.bos.dataentity.entity.DynamicObject;
import kd.bos.dataentity.entity.DynamicObjectCollection;
import kd.bos.dataentity.entity.LocaleString;
import kd.bos.dataentity.metadata.IDataEntityProperty;
import kd.bos.dataentity.metadata.IDataEntityType;
import kd.bos.dataentity.metadata.clr.DataEntityPropertyCollection;
import kd.bos.dataentity.metadata.dynamicobject.DynamicObjectType;
import kd.bos.entity.plugin.AbstractOperationServicePlugIn;
import kd.bos.entity.plugin.PreparePropertysEventArgs;
import kd.bos.entity.plugin.args.BeforeOperationArgs;
import kd.bos.entity.property.EntryProp;
import kd.bos.orm.query.QCP;
import kd.bos.orm.query.QFilter;
import kd.bos.servicehelper.AttachmentServiceHelper;
import kd.bos.servicehelper.BusinessDataServiceHelper;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import zmee.bid.oa.OAutil;
import zmee.common.allenum.OaAuditFlowResultEnum;

import javax.xml.soap.*;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author yss
 * @createTime 2022-11-14 10:10
 * @description 支出合同扩展审核插件
 */
public class OutContractExtOp extends AbstractOperationServicePlugIn {
    //public class OutContractExtOp extends OutContractOp {
    private static Log logger = LogFactory.getLog(OutContractExtOp.class);
    /**
     * 测试环境地址
     */
//    private final String OA_TEST = "https://apitest1.wzgroup.cn";
////    private final String OA_TEST = "http://oatest.wzgroup.cn/";
//    /** 创建工作流地址 */
//    private final String CREATE_WORKFLOW_REQUEST="/env-101/por-1/oa/OAdj_route/doCreateWorkflowRequest";

    private final String OA_ADUIT_PARAM_SOAPENV = "oaflow";
    private final String OA_ADUIT_URL = "oaflowsoapenv";
    /**
     * apikey - 固定写法，暂时不知道什么意义
     */
    private final String apikey = "VyL98PvnXRo1eoRtNsS2TsYpzXVKOLoQ";
    /**
     * 环能实业-合同审批流程 id
     */
    private final String WORK_FLOW_ID_HUANNENG = "3852";
    /**
     * 环能实业-山鹰热电合同审批流程 id
     */
    private final String WORK_FLOW_ID_SHANYING = "100272";
    /**
     * 环能实业-合同审批流程 名称
     */
    private final String WORK_FLOW_NAME_HUANNENG = "环能实业-合同审批流程";
    /**
     * 环能实业-山鹰热电合同审批流程 名称
     */
    private final String WORK_FLOW_NAME_SHANYING = "环能实业-山鹰热电合同审批流程";
    /**
     * OA实体id字段
     */
    private final String OAID = "oaid";

    @Override
    public void onPreparePropertys(PreparePropertysEventArgs e) {
        super.onPreparePropertys(e);
        List<String> fieldKeys = e.getFieldKeys();
        fieldKeys.addAll(this.billEntityType.getAllFields().keySet());
    }

    @Override
    public void beforeExecuteOperationTransaction(BeforeOperationArgs e) {
        DynamicObject[] dataEntities = e.getDataEntities();
        String key = e.getOperationKey();
        if ("submit".equals(key)) {
            List<String> isError = new ArrayList<>();
            for (DynamicObject outContractDy : dataEntities) {
                DynamicObject data = BusinessDataServiceHelper.loadSingle(outContractDy.getPkValue(), outContractDy.getDynamicObjectType());
                String billno = data.getString("billno");
                if (!data.getString("zmee_combofield").equals("01")) {
                    logger.info("合同编码：" + billno + ";开始进行OA调用！");
                    //审核时调用oa接口，创建oa工作流
                    String workFlowResult = creatOutContractAuditWorkFlow(createOutContractAuditBody(outContractDy));
                    isError.add(String.format("单据号%s，%s", outContractDy.getString("billno"), workFlowResultResolve(workFlowResult)));
                }
            }
            String result = "";
            if (isError.size() > 0) {
                result = String.join(",", isError);
            } else {
                result = "审核成功，等待oa审批结果。。。";
            }
            e.setCancelMessage(result);
        }
    }

    protected String creatOutContractAuditWorkFlow(String body) {
        logger.info(String.format("OA连接报文：%s", body));
        String url = getConfigurationByNumber(OA_ADUIT_URL);
        logger.info("生产环境的：OA调用连接的地址 URL = " + url + "apikey=" + apikey);
        //创建支出合同审批流程
        String workFlowResult = HttpRequest.post(String.format("%s?apikey=%s", url, apikey))
                .header("Content-Type", "application/xml")
                .body(body)
                .timeout(20000)
                .execute().body();
        logger.info(String.format("创建流程为：%s", workFlowResult));
        return workFlowResult;
    }

    protected String workFlowResultResolve(String soapXML) {
        //解析soap字符串
        String soapResultStr = "";
        try {
            SOAPMessage msg = formatSoapString(soapXML);
            SOAPBody body = msg.getSOAPBody();
            Iterator<SOAPElement> bodyIterator = body.getChildElements();
            soapResultStr = soapResult(bodyIterator);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("workFlowResultResolve - 捕抓异常：" + e);
        }
        logger.info(String.format("工作流程处理结果为：%s", soapResultStr));
        return OaAuditFlowResultEnum.getMag(soapResultStr);
    }

    private static String soapResult(Iterator<SOAPElement> bodyIterator) {
        String soapResultStr = "";
        while (bodyIterator.hasNext()) {
            //<ns1:out>-2</ns1:out>
            SOAPElement bodySOAPElement = bodyIterator.next();
            String localName = bodySOAPElement.getLocalName();//out
            String nodeName = bodySOAPElement.getNodeName();//ns1:out
            String tagName = bodySOAPElement.getTagName();//ns1:out
            String value = bodySOAPElement.getValue();//-2
            if ("ns1:out".equals(nodeName)) {
                soapResultStr = value;
                break;
            }
            if (null == bodySOAPElement.getValue()
                    && bodySOAPElement.getChildElements().hasNext()) {
                soapResultStr = soapResult(bodySOAPElement.getChildElements());
            }
        }
        return soapResultStr;
    }

    /**
     * 把soap字符串格式化为SOAPMessage
     *
     * @param soapString
     * @return
     * @see [类、类#方法、类#成员]
     */
    private static SOAPMessage formatSoapString(String soapString) {
        MessageFactory msgFactory;
        try {
            msgFactory = MessageFactory.newInstance();
            SOAPMessage reqMsg = msgFactory.createMessage(new MimeHeaders(),
                    new ByteArrayInputStream(soapString.getBytes("UTF-8")));
            reqMsg.saveChanges();
            return reqMsg;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("formatSoapString - 捕抓异常：" + e);
            return null;
        }
    }

    /**
     * 创建请求body信息
     *
     * @param outContractDy
     * @return
     */
    protected String createOutContractAuditBody(DynamicObject outContractDy) {
        DynamicObject creatorDy = outContractDy.getDynamicObject("zmee_oauserfield");//登陆人
        //创建人工号
        String creatorStr = "";
        if (creatorDy != null) {
            creatorStr = creatorDy.getString("username");
        }

        //创建支出合同审批流程body
        StringBuilder bodyInfo = new StringBuilder();
        String bodyHeadStr = String.format("<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:fron=\"%s\" xmlns:web=\"http://webservices.workflow.weaver\">", getConfigurationByNumber(OA_ADUIT_PARAM_SOAPENV));
        bodyInfo.append(bodyHeadStr);
        bodyInfo.append("<soapenv:Header/>");
        bodyInfo.append("<soapenv:Body>");
        bodyInfo.append("<fron:doCreateWorkflowRequest>");
        bodyInfo.append("<fron:in0>");

        /*账号类型：1，账号；2 标识号；3分配号，必须传*/
        bodyInfo.append("<web:accountType>1</web:accountType>");
        /*账号值，必须传*/
//        String userid = String.format("<web:userid>%s</web:userid>","xuym1");
        String userid = String.format("<web:userid>%s</web:userid>", creatorStr);
        bodyInfo.append(userid);
        /*流程信息，必须传*/
        bodyInfo.append("<web:workflowRequestInfo>");
        //请求信息
        String requestLevel = String.format("<web:requestLevel>%s</web:requestLevel>", "0");
        bodyInfo.append(requestLevel);
        //oa人员信息，目前写死 苍穹人员工号 = oa人员id
        String creatorId = String.format("<web:creatorId>%s</web:creatorId>", creatorStr);
//        String creatorId = String.format("<web:creatorId>%s</web:creatorId>","8955");
        bodyInfo.append(creatorId);
        /*请求标题*/
        String fBillName = outContractDy.getString("billname");//合同名称
        String requestName = String.format("<web:requestName>%s</web:requestName>", fBillName);
        bodyInfo.append(requestName);
        //停留在创建节点
        //bodyInfo.append("<web:isnextflow>0</web:isnextflow>");
        /*工作流信息 - 根据组织进行判断*/
        bodyInfo.append("<web:workflowBaseInfo>");
        //环能实业-合同审批流程 3852
        //环能实业-山鹰热电合同审批流程  100272
        boolean isOa = true;//判断是否为环能实业-合同审批流程
        String workflowId = String.format("<web:workflowId>%s</web:workflowId>", isOa ? WORK_FLOW_ID_HUANNENG : WORK_FLOW_ID_SHANYING);//工作流ID，必传
        bodyInfo.append(workflowId);
        String workflowName = String.format("<web:workflowName>%s</web:workflowName>", isOa ? WORK_FLOW_NAME_HUANNENG : WORK_FLOW_NAME_SHANYING);//工作流标题
        bodyInfo.append(workflowName);
        bodyInfo.append("</web:workflowBaseInfo>");

        /*主表信息*/
        bodyInfo.append("<web:workflowMainTableInfo>");
        bodyInfo.append("<web:requestRecords>");
        bodyInfo.append("<web:WorkflowRequestTableRecord>");
        bodyInfo.append("<web:recordOrder>1</web:recordOrder>");//行号
        bodyInfo.append("<web:workflowRequestTableFields>");
        List<Map<String, String>> billHeadInfo = new ArrayList<>();
        Map<String, List<Map<String, String>>> billEntryInfo = new HashMap<>();
//        getDyAllInfo(billHeadInfo,billEntryInfo,outContractDy);
        getInterfaceParams(billHeadInfo, billEntryInfo, outContractDy, isOa);

        /* 单据头内容 - 这边循环 */
        //传参基本数据
        for (Map<String, String> headInfo : billHeadInfo) {
            bodyInfo.append("<web:WorkflowRequestTableField>");
            //是否可编辑，得传true
            String edit = headInfo.get("edit");
            String editAppend = String.format("<web:edit>%s</web:edit>", StringUtils.isEmpty(edit) ? true : edit);
            bodyInfo.append(editAppend);
            //字段名称
            String fieldName = headInfo.get("fieldName");
            String fieldNameAppend = String.format("<web:fieldName>%s</web:fieldName>", fieldName);
            bodyInfo.append(fieldNameAppend);
            //字段值
            String fieldValue = headInfo.get("fieldValue");
            if ("fj".equals(fieldName)) {
                logger.info("我是附件，fieldValue = " + fieldValue);
                // 如果是附件就不进行XML的转换。
                String fieldValueAppend = String.format("<web:fieldValue>%s</web:fieldValue>", fieldValue);
                bodyInfo.append(fieldValueAppend);
            } else {
                String fieldValueAppend = String.format("<web:fieldValue>%s</web:fieldValue>", StringEscapeUtils.escapeXml(fieldValue));
                bodyInfo.append(fieldValueAppend);
            }
            //字段值
            String fieldType = headInfo.get("fieldType");
            if (StringUtils.isNotEmpty(fieldType)) {
                String fieldTypeAppend = String.format("<web:fieldType>%s</web:fieldType>", fieldType);
                bodyInfo.append(fieldTypeAppend);
            }
            //是否可见，得传true
            String view = headInfo.get("view");
            String viewAppend = String.format("<web:view>true</web:view>", StringUtils.isEmpty(view) ? true : view);
            bodyInfo.append(viewAppend);
            bodyInfo.append("</web:WorkflowRequestTableField>");
        }

        bodyInfo.append("</web:workflowRequestTableFields>");
        bodyInfo.append("</web:WorkflowRequestTableRecord>");
        bodyInfo.append("</web:requestRecords>");
        bodyInfo.append("</web:workflowMainTableInfo>");

        if (!billEntryInfo.isEmpty()) {
            /* 单据体内容 - 这边循环 */
            bodyInfo.append("<web:workflowDetailTableInfos>");
            bodyInfo.append("<web:WorkflowDetailTableInfo>");
            bodyInfo.append("<web:workflowRequestTableRecords>");

            for (Map.Entry<String, List<Map<String, String>>> billEntry : billEntryInfo.entrySet()) {
                String key = billEntry.getKey();//单据体名称
                List<Map<String, String>> billEntryValue = billEntry.getValue();//单据体详情
                //循环单据体的每一行
                bodyInfo.append("<web:WorkflowRequestTableRecord>");

                for (Map<String, String> billEntryMap : billEntryValue) {
                    bodyInfo.append("<web:workflowRequestTableFields>");
                    //第几行
                    String row = billEntryMap.get("row");
                    String rowAppend = String.format("<web:recordOrder>%s</web:recordOrder>", row);
                    bodyInfo.append(rowAppend);
                    bodyInfo.append("<web:WorkflowRequestTableField>");
                    //是否可编辑，得传true
                    String edit = billEntryMap.get("edit");
                    String editAppend = String.format("<web:edit>%s</web:edit>", StringUtils.isEmpty(edit) ? true : edit);
                    bodyInfo.append(editAppend);
                    //字段名称
                    String fieldName = billEntryMap.get("fieldName");
                    String fieldNameAppend = String.format("<web:fieldName>%s</web:fieldName>", fieldName);
                    bodyInfo.append(fieldNameAppend);
                    //字段值
                    String fieldValue = billEntryMap.get("fieldValue");
                    String fieldValueAppend = String.format("<web:fieldValue>%s</web:fieldValue>", StringEscapeUtils.escapeXml(fieldValue));
                    bodyInfo.append(fieldValueAppend);
                    //是否可见，得传true
                    String view = billEntryMap.get("view");
                    String viewAppend = String.format("<web:view>true</web:view>", StringUtils.isEmpty(view) ? true : view);
                    bodyInfo.append(viewAppend);
                    bodyInfo.append("</web:WorkflowRequestTableField>");
                    bodyInfo.append("</web:workflowRequestTableFields>");
                }
                bodyInfo.append("</web:WorkflowRequestTableRecord>");
            }
            bodyInfo.append("</web:workflowRequestTableRecords>");
            bodyInfo.append("</web:WorkflowDetailTableInfo>");
            bodyInfo.append("</web:workflowDetailTableInfos>");
        }

        bodyInfo.append("</web:workflowRequestInfo>");
        bodyInfo.append("</fron:in0>");
        bodyInfo.append("</fron:doCreateWorkflowRequest>");
        bodyInfo.append("</soapenv:Body>");
        bodyInfo.append("</soapenv:Envelope>");
        return bodyInfo.toString();//StringEscapeUtils.escapeXml(bodyInfo.toString());
    }

    /**
     * 获取接口参数
     *
     * @param billHeadInfo
     * @param billEntryInfo
     * @param outContractDy
     * @param isOa
     */
    private void getInterfaceParams(List<Map<String, String>> billHeadInfo, Map<String, List<Map<String, String>>> billEntryInfo,
                                    DynamicObject outContractDy, boolean isOa) {
        if (isOa) {
            createFieldOaInfo(billHeadInfo, billEntryInfo, outContractDy);
        } else {
            createFieldNotOaInfo(billHeadInfo, billEntryInfo, outContractDy);
        }
    }

    private void createFieldOaInfo(List<Map<String, String>> billHeadInfo, Map<String, List<Map<String, String>>> billEntryInfo,
                                   DynamicObject outContractDy) {
        DynamicObjectCollection outContPayPlanEntry = outContractDy.getDynamicObjectCollection("outcontpayplanentry");

//      标题 lcbh
//        billHeadInfo.add(getFieldInfoMap("true","sqdw",getOaId(orgDy),"true","0",null));
//      流程编号 lcbh
//ok        申请公司 sqdw	org.number
        DynamicObject orgDy = outContractDy.getDynamicObject("org");
        billHeadInfo.add(getFieldInfoMap("true", "sqdw", getOaId(orgDy), "true", "0", null));
//        关联表单号 glbdh
//ok        合同编号 htbh	billno
        String billnoStr = outContractDy.getString("billno");
        billHeadInfo.add(getFieldInfoMap("true", "htbh",
                StringUtils.isEmpty(billnoStr) ? "" : billnoStr, "true", "0", null));
//ok        申请人 sqr	creator.number
        DynamicObject creatorDy = outContractDy.getDynamicObject("zmee_oauserfield");
        billHeadInfo.add(getFieldInfoMap("true", "sqr", getOaId(creatorDy), "true", "0", null));
        billHeadInfo.add(getFieldInfoMap("true", "sfwbcxy", "0", "true", "0", null));

        //来源系统
        billHeadInfo.add(getFieldInfoMap("true", "sourcefrom", "优采云", "true", "0", null));
        billHeadInfo.add(getFieldInfoMap("true", "sourfrom", "2", "true", "0", null));

//ok        合同承办部门 htcbbm	fiaccountorg.number
//        DynamicObject fiaccountorgDy = outContractDy.getDynamicObject("fiaccountorg");
        //获取创建人信息的组织信息中第一个组织的oaid
        DynamicObject dptDy = outContractDy.getDynamicObject("htcbbm");
        billHeadInfo.add(getFieldInfoMap("true", "htcbbm", getOaId(dptDy), "true", "0", null));
        String contractnature = outContractDy.getString("zmee_contractnature");
        billHeadInfo.add(getFieldInfoMap("true", "htxz", contractnature, "true", "0", null));
//        合同类型 htlx	contracttype
        String contracttype = outContractDy.getString("zmee_contracttype");
        billHeadInfo.add(getFieldInfoMap("true", "htlx", contracttype, "true", "0", null));

//ok        合同标的金额 htbdje	originaloftaxamount
        BigDecimal originaloftaxamount = outContractDy.getBigDecimal("originaloftaxamount");
        billHeadInfo.add(getFieldInfoMap("true", "htbdje", String.valueOf(originaloftaxamount), "true", "0", null));

//          收付款类型 sfklx	outcontpayplanentry。paytype
        String paytype = outContractDy.getString("zmee_accandpaytype");
        billHeadInfo.add(getFieldInfoMap("true", "sfklx", paytype, "true", "0", null));

//ok          收付款方式 sfkfs	outcontpayplanentry.payway  	4-其他 ;JSFS04	0-电汇;3-混合付款;JSFS06 1-商业汇票;JSFS08	2-信用证
        String payway = outContractDy.getString("zmee_accandpayway");
        billHeadInfo.add(getFieldInfoMap("true", "sfkfs", payway, "true", "0", null));
//        授信额度（赊销及预付款）ssed
        String limitOfCreditStr = outContractDy.getString("zmee_limitofcredit");
        billHeadInfo.add(getFieldInfoMap("true", "ssed", limitOfCreditStr, "true", "0", null));
//        已使用额度 ysyed
        String usedLimitStr = outContractDy.getString("zmee_usedlimit");
        billHeadInfo.add(getFieldInfoMap("true", "ysyed", usedLimitStr, "true", "0", null));
//        可使用额度 ksyed
        String useLimitStr = outContractDy.getString("zmee_uselimit");
        billHeadInfo.add(getFieldInfoMap("true", "ksyed", useLimitStr, "true", "0", null));
//        备注（对于分期收付款的写明收付款节点及交货进度及验收要求及履约保证金及质保金退还规则）bz
        String zmeeDescriptionStr = outContractDy.getString("zmee_description");
        billHeadInfo.add(getFieldInfoMap("true", "bz", zmeeDescriptionStr, "true", "0", null));
//        合同文本（附件）fj - zmee_contractaccessory  zmee_imageaccessory
        setAccessoryField(outContractDy, "zmee_contractaccessory", "fj", billHeadInfo);
//      List<String> contractAccessoryUrlList = getKingDeeAttachmentUrlAdaptiveOAList(outContractDy, "zmee_contractaccessory");
//        billHeadInfo.add(getFieldInfoMap("true","fj",String.join(",",contractAccessoryUrlList),"true","0",null));
//        备注 bz1 description
        String descriptionStr = outContractDy.getString("description");
        billHeadInfo.add(getFieldInfoMap("true", "bz1", descriptionStr, "true", "0", null));

//        是否有会审部门 sfyhsbm isreport
        Boolean isreport = outContractDy.getBoolean("zmee_isreport");
        billHeadInfo.add(getFieldInfoMap("true", "sfyhsbm", isreport ? "0" : "1", "true", "0", null));
//        会审部门 hsbm reportorg
        DynamicObject reportorgDy = outContractDy.getDynamicObject("zmee_reportorg");
        billHeadInfo.add(getFieldInfoMap("true", "hsbm", getOaId(reportorgDy), "true", "0", null));
//        流程单号 lcdh
        billHeadInfo.add(getFieldInfoMap("true", "fk_zmee_zclcnumber", outContractDy.getString("zmee_zclcnumber"), "true", "0", null));
//        合同相对人 htxdr
        DynamicObject partbDy = outContractDy.getDynamicObject("partb");
        if (partbDy != null) {
            billHeadInfo.add(getFieldInfoMap("true", "htxdr", String.valueOf(partbDy.getString("name")), "true", "0", null));
        }
//        泰爱斯归档抄送人 tasgdcsr
//        浦江热电归档抄送人 tasgdcsr
//        分管领导 fgld
//        景宁水务归档抄送人 jnswgdcsr
//        新嘉爱斯归档抄送人 xjasgdcsr
//        影像扫描件 smj
        setAccessoryField(outContractDy, "zmee_imageaccessory", "smj", billHeadInfo);
//        List<String> imageAccessoryUrlList =  getKingDeeAttachmentUrlAdaptiveOAList(outContractDy, "zmee_imageaccessory");
//        billHeadInfo.add(getFieldInfoMap("true","smj",String.join(",",imageAccessoryUrlList),"true","0",null));
//        移动端扫描件 appsmj
//        抄送蔡琳 cs
//        抄送沈翔 cs1
//        环能浦江热电-商务部负责人（曹允宁、冯一帆） swbfzr
//        单据号 barcode	billno
        billHeadInfo.add(getFieldInfoMap("true", "barcode",
                StringUtils.isEmpty(billnoStr) ? "" : billnoStr, "true", "0", null));

//        billEntryInfo.put("outcontpayplanentry",entryList);
    }

    private void createFieldNotOaInfo(List<Map<String, String>> billHeadInfo, Map<String, List<Map<String, String>>> billEntryInfo,
                                      DynamicObject outContractDy) {
//        公司	gs fiaccountorg
        DynamicObject fiaccountorgDy = outContractDy.getDynamicObject("fiaccountorg");
        billHeadInfo.add(getFieldInfoMap("true", "gs",
                fiaccountorgDy == null ? "" : fiaccountorgDy.getString("number"), "true", "0", null));
//        部门	bm org
        DynamicObject orgDy = outContractDy.getDynamicObject("org");
        billHeadInfo.add(getFieldInfoMap("true", "bm", getOaId(orgDy), "true", "0", null));
//        编制人	bzr
//        预算表编码	ysbbm budgetitem.number
        DynamicObject budgetitemDy = outContractDy.getDynamicObject("budgetitem");
        billHeadInfo.add(getFieldInfoMap("true", "ysbbm", getOaId(budgetitemDy), "true", "0", null));
//        预算表名称	ysbmc budgetitem.name
//        时间	sj new Date();
        billHeadInfo.add(getFieldInfoMap("true", "sj",
                String.valueOf(new Date()), "true", "0", null));
//        表单性质	bdxz 0-新增;1-调整
        billHeadInfo.add(getFieldInfoMap("true", "bdxz", "0", "true", "0", null));
//        附件	fj
//        备注	bzr
//        单据号	barcode	billno

    }

    private String getOaId(DynamicObject dy) {
        if (dy == null) {
            return "";
        }
        DynamicObject oaDy = BusinessDataServiceHelper.loadSingle(dy.getLong("id"), dy.getDynamicObjectType().getName(), OAID);
        if (oaDy == null) {
            return "";
        }
        return oaDy.getString(OAID);
    }

    private void getDyAllInfo(List<Map<String, String>> billHeadInfo, Map<String, List<Map<String, String>>> billEntryInfo, DynamicObject outContractDy) {
        DynamicObjectType outContractDyType = outContractDy.getDynamicObjectType();
        DataEntityPropertyCollection properties = outContractDyType.getProperties();
        for (IDataEntityProperty propertie : properties) {
            String propertieName = propertie.getName();
            //判断字段类型
            boolean isEntry = propertie instanceof EntryProp;
            List<Map<String, String>> propertieList = createFieldInfo(propertie, outContractDy, isEntry ? propertieName : null, 0);
            if (isEntry) {
                billEntryInfo.put(propertieName, propertieList);
            } else {
                billHeadInfo.addAll(propertieList);
            }
        }
    }

    private List<Map<String, String>> createFieldInfo(IDataEntityProperty pro, DynamicObject dy, String entryName, int row) {
        List<Map<String, String>> billInfoList = new ArrayList<>();
        String propertieName = pro.getName();
        if (StringUtils.isNotEmpty(entryName)) {//为单据体信息
            DynamicObjectCollection entryDyCo = dy.getDynamicObjectCollection(propertieName);
            for (int i = 0; i < entryDyCo.size(); i++) {
                DynamicObject entryDy = entryDyCo.get(i);//第几行数据
                DynamicObjectType entryDyType = entryDy.getDynamicObjectType();
                DataEntityPropertyCollection properties = entryDyType.getProperties();
                for (IDataEntityProperty property : properties) {
                    billInfoList.addAll(createFieldInfo(property, entryDy, null, i));
                }
            }

        } else {//为单据头信息
            Object fieldObject = dy.get(propertieName);
            LocaleString displayName = pro.getDisplayName();
            billInfoList.add(getFieldInfoMap("true", displayName != null ? displayName.getLocaleValue() : propertieName,
                    getFieldValue(fieldObject, dy), "true", "0", null));
        }
        return billInfoList;
    }

    private String getFieldValue(Object fieldObject, DynamicObject parentDy) {
        String fieldValue = "";
        if (fieldObject instanceof DynamicObject) {//实体类
            DynamicObject fieldDy = (DynamicObject) fieldObject;
            fieldValue = getDynamicObjectColumShow(fieldDy);
        } else if (fieldObject instanceof DynamicObjectCollection) {//实体集合
            //判断集合数据
            DynamicObjectCollection fieldDyCo = (DynamicObjectCollection) fieldObject;
            List<String> childDyValueList = new ArrayList<>();
            for (DynamicObject fieldDy : fieldDyCo) {
                childDyValueList.add(getDynamicObjectColumShow(fieldDy));
            }
            fieldValue = String.join(",", childDyValueList);
        }
        return fieldValue;
    }

    private String getDynamicObjectColumShow(DynamicObject fieldDy) {
        IDataEntityType fieldDyType = fieldDy.getDataEntityType();
        DataEntityPropertyCollection properties = fieldDyType.getProperties();
        String fieldValue = "";
        for (IDataEntityProperty property : properties) {
            String propertyName = property.getName();
            if ("name".equals(propertyName)) {//当前实体存在名称字段
                fieldValue = fieldDy.getString(propertyName);
                break;
            } else if ("billno".equals(propertyName)) {
                fieldValue = fieldDy.getString(propertyName);
                break;
            } else if ("fbasedataid".equals(propertyName)) {//多选基础资料
                DynamicObject fbasedataidDy = fieldDy.getDynamicObject(propertyName);
                fieldValue = getDynamicObjectColumShow(fbasedataidDy);
            }
        }
        return fieldValue;
    }

    private Map<String, String> getFieldInfoMap(String editStr, String fieldNameStr, String fieldValueStr, String viewStr, String rowStr, String fieldType) {
        Map<String, String> fieldInfoMap = new HashMap<>();
        fieldInfoMap.put("edit", editStr);
        fieldInfoMap.put("fieldName", fieldNameStr);
        fieldInfoMap.put("fieldValue", fieldValueStr);
        fieldInfoMap.put("view", viewStr);
        fieldInfoMap.put("row", rowStr);
        if (StringUtils.isNotEmpty(fieldType)) {
            fieldInfoMap.put("fieldType", fieldType);
        }
        return fieldInfoMap;
    }


    private void setAccessoryField(DynamicObject dy, String kingDeeStr, String oaStr, List<Map<String, String>> billInfoList) {
        if (dy != null && StringUtils.isNotEmpty(kingDeeStr)) {
            String dyName = dy.getDynamicObjectType().getName();
            long dyPk = dy.getLong("id");
            List<Map<String, Object>> attachList = AttachmentServiceHelper.getAttachments(dyName, dyPk, kingDeeStr);
            List<Map<String, String>> mapUrl = OAutil.urlList(attachList, oaStr);
            for (Map<String, String> urlInfo : mapUrl) {
                billInfoList.add(getFieldInfoMap("true", oaStr, urlInfo.get("fieldValue"), "true", "0", urlInfo.get("fieldType")));
            }
        }
    }

    /**
     * 获取配置地址中的地址信息
     *
     * @param urlNumber
     * @return
     */
    private String getConfigurationByNumber(String urlNumber) {
        DynamicObject urlDy = BusinessDataServiceHelper.loadSingleFromCache("zmee_configuration", "url", new QFilter[]{new QFilter("number", QCP.equals, urlNumber)});
        if (urlDy == null) {
            return "";
        }
        return urlDy.getString("url");
    }
}